package chat1.server;

import chat1.server.dao.UserDao;
import chat1.server.utils.IOUtil;
import chat1.server.vo.UserInfo;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.HashMap;

public class Server {
    ServerSocket  ss=null;
    public static  final  byte  LOGIN=1;//客户端发送数据+ 一个byte类型的整数(客户端要进行的操作)
    public static  final  byte  REGISTER=2;//注册
    public static  final  byte  SEND_TEXT=3;//聊天

    //服务端返回数据的时候，同时一个byte类型的整数(表示处理的是客户端的那种请求)
    public static  final  byte LOGIN_RESPONSE=1;//表示服务端给客户端返回的数据处理的是登录请求的结果
    public static  final  byte  REGISTER_RESPONSE=2;//注册
    public static  final  byte  SEND_TEXT_TOALL_RESPONSE=3;
    public static  final  byte  USER_LIST_RESPONSE=4;//某个客户端登录后，就要服务端发请求
    // (发送用户名给服务端)(服务端让所有客户端更新好友列表)
    HashMap<String, UserInfo>  users=new HashMap();
    public static void main(String[] args) throws IOException {
        Server ser=new Server();//1.创建Server对象,构造中开启8088
        ser.start();//2.start方法  accept等待客户端连接     如果连接 创建线程。
    }



    Server() throws IOException {//1.开启8088端口
        ss=new ServerSocket(8088);
    }

    public void start() throws IOException {//2.start方法中用accept等待客户端连接
        while(true){//用循环调用accept()  为了让很多客户端都可以连接服务器
            System.out.println("服务端启动成功，等待客户端连接...");
            Socket s=ss.accept();   //如果客户端连接了，就开启一个线程处理此客户端的请求
            System.out.println(s.getInetAddress()+"客户端连接服务端成功");
            ClientService  cs=new ClientService(s);
            cs.start();
        }
    }



    //每次一个客户端连接到server，就开启一个ClientService线程
    //读取客户端的数据，并且进行对应的操作(登录). 返回操作的结果
    class ClientService  extends  Thread{
        Socket  socket;
        ClientService(Socket  so){
            socket=so;
        }
        InputStream in;//用socket获取输入流赋值给in
        OutputStream out;//用socket获取输出流赋值给out
        UserInfo  userInfo;//当前发送数据的用户(对象)






        public void reShowFriendList() throws IOException {
            StringBuffer friendsInfo=new StringBuffer();//空字符串
            //从本类中上边HashMap中获取所有的好友信息，拼接成一个字符串。
            for(String    user :  users.keySet() ){
                friendsInfo.append(user+",");
            }
            //获取好友列表中每个好友的输出流，将好友列表发送给每个客户端
            //UserInfo用来操作数据用户的类(username, pwd, Socket)
            for(UserInfo    userInfo :users.values()){
                OutputStream out=userInfo.getSocket().getOutputStream();
                IOUtil.writeShort(USER_LIST_RESPONSE,out);
                //给客户端返回的数据是USER_LIST_RESPONSE更新好友列表的数据
                IOUtil.writeString(friendsInfo.toString(),  out);
            }
        }



        public void doRegist() throws Exception {//接收客户端发送的账号密码，保存起来，
            int flag = -1;//表示是否注册成功//1.注册操作
            try {
                // 给客户端返回注册成功或失败(同时发送一个byte数据表示返回的是注册的结果)
                String username = IOUtil.readString(in);//用工具类读取客户端发送账号密码
                String password = IOUtil.readString(in);
                UserDao.addUser(new UserInfo(username, password));//将数据用UserDao.addUser保存到数据
                flag = 1;//flag赋值为1表示保存成功
                userInfo = new UserInfo(username, password);
                userInfo.setSocket(socket);//2.服务端更新好友列表
                users.put(username, userInfo);//将当前注册成功的用于存入到服务端的用户列表
            }catch (Exception  e){
                IOUtil.writeShort(REGISTER_RESPONSE,out);
                IOUtil.writeString("register  error",out);
                flag=-1;//注册异常，  用IOUtil给客户端返回一个  register error 同时返回 2表示注册结果
            }
            if(flag==1){
                IOUtil.writeShort(REGISTER_RESPONSE,out);//注册成功返回2，表示本次返回的是注册的结果
                IOUtil.writeString("register success",out);
            }
            reShowFriendList();
        }



        public void run(){
            try {
                in=socket.getInputStream();
                out=socket.getOutputStream();
                int command=-1;//用此变量表示客户端的操作
                //比如说 客户端要登录就发command的值为某个整数，要注册发送另一个整数
                while(  (command=in.read())!=-1 ){
                    switch (command){
                        case REGISTER:
                            doRegist();//如果客户端发送的注册数据，就执行注册方法
                            reShowFriendList();//更新好友列表
                            break;
                        case LOGIN:
                            doLogin();//如果客户端发送的登录数据，就执行登录方法
                            reShowFriendList();//更新好友列表
                            break;
                        case SEND_TEXT://如果客户端发送的群发数据，就执行群发消息方法
                            sendMessageToAll();
                            break;
                    }
                }
            } catch (Exception e) {
                System.out.println("一个客户端下线了");
            }finally {
                //客户端出异常(网络，或者客户端自己关闭)//userInfo当前登录的用户
                if(users!=null && users.size()!=0&&userInfo!=null
                        &&userInfo.getUsername()!=null){
                    users.remove(userInfo.getUsername());//A.客户端出现异常就把它从好友列表中删除
                }
                try {
                    reShowFriendList();//B.同时更新好友列表
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }


    }




}

